package com.eugenema.util.DemandUtil;

import com.alibaba.excel.util.StringUtils;
import com.eugenema.entity.EvenMatch;
import com.eugenema.entity.FutureMatch;
import com.eugenema.entity.Team;
import com.eugenema.entity.TestStep;
import com.eugenema.service.RunSeleniumService;
import com.eugenema.util.SeleniumUtil;
import com.eugenema.util.SeleniumXmlParseUtil;
import com.eugenema.windowGui.controller.HomeDetailController;
import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
 * <p>标题：联赛工具类</p>
 * <p>
 *  功能：包含与联赛相关的工具方法
 * </p>
 * <p>其他说明：</p>
 * <p>作者：马寅广</p>
 * <p>审核：</p>
 * <p>重构：</p>
 * <p>创建日期：2023/12/31 20:58</p>
 */
public class LeagueMatchUtil {
    /** 日志 */
    private static Logger logger = LoggerFactory.getLogger(LeagueMatchUtil.class);
    /** 比赛日期格式 */
    private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm");

    /**
     * 遍历联赛
     * <br/>从联赛界面进入球队界面
     * <br/>在联赛界面获取所有的球队信息，并遍历球队信息
     *
     * @param service 脚本服务
     * @param leagueParameterKey 要读取的联赛列表参数的 key
     * @param everyLeagueStartlDeal 每个联赛处理前，函数式接口传入的参数是当前遍历的联赛名称
     * @param everyTeamDeal 遍历球队时，要执行的方法。函数式接口传入的参数是单双数列表，及当前遍历球队的名及链接：map<球队名称，球队链接>
     * @param everyLeagueFinalDeal 每个联赛处理后，函数式接口传入的参数是当前遍历的联赛名称
     *
     * @author 马寅广
     *
     * @date 2023/3/15 10:24
     **/
    public static void leagueToTeam(RunSeleniumService service, String leagueParameterKey, Consumer<String> everyLeagueStartlDeal, BiConsumer<List<String>, Map.Entry<String, String>> everyTeamDeal, Consumer<String> everyLeagueFinalDeal) {
        //遍历指定联赛
        Map<String, String> leagueParameter = (Map<String, String>) SeleniumXmlParseUtil.parameterMap.get(leagueParameterKey);
        logger.info("共有【{}】个联赛~", leagueParameter.size());

        /** 当前处理的联赛索引，从 1 开始 */
        int index = 1;
        for (Map.Entry<String, String> leagueEntry : leagueParameter.entrySet()) {
            logger.info("***** 联赛处理进度：【{}/{}】 *****", index++, leagueParameter.size());

            //打开联赛首页
            TestStep step_1 = service.getStep("step_1");
            step_1.setValue(leagueEntry.getValue());
            service.runStep(step_1);

            //获取联赛名称
            service.runStep("step_2");
            String leagueName = ((List<WebElement>) SeleniumUtil.globalMap.get("step_2")).get(0).getText().replaceAll("^\\[|\\]$", "");

            //调用联赛处理方法
            everyLeagueStartlDeal.accept(leagueName);
            logger.info("【{}】联赛开始处理", leagueName);

            //获取球队列表
            service.runStep("step_3");
            List<WebElement> teamList = (List<WebElement>) SeleniumUtil.globalMap.get("step_3");
            /** map<球队名称, 链接> */
            Map<String, String> teamMap = teamList.stream().collect(Collectors.toMap(WebElement -> WebElement.getAttribute("title"), WebElement -> WebElement.getAttribute("href"), (a, b) -> b, LinkedHashMap::new));

            //对球队遍历方法体进行增强：在执行前，先获取最近 30 场比赛单双数数据，并且在调用方法时，将当前遍历的球队信息传入
            Consumer<Map.Entry<String, String>> enhanceMethod = teamEntry -> {
                //获取近期战绩的所有单双信息
                service.runStep("step_5");
                List<WebElement> matchList = (List<WebElement>) SeleniumUtil.globalMap.get("step_5");
                /** 单双信息 */
                List<String> sinOrDouList = matchList.stream().map(match -> match.getAttribute("textContent")).collect(Collectors.toList());
                //执行球队遍历方法体
                everyTeamDeal.accept(sinOrDouList, teamEntry);
            };

            // 遍历球队，处理球队信息
            teamDeal(service, teamMap, enhanceMethod);

            //执行单个联赛运行完的方法体
            everyLeagueFinalDeal.accept(leagueName);
        }
    }

    /**
     * 球队信息处理
     * <br/>遍历球队 map，执行相应动作
     *
     * @param service 脚本服务
     * @param teamMap 球队 map<球队名称, 球队链接>
     * @param everyTeamDeal 遍历球队要执行的方法，函数式接口传入的参数是当前遍历球队的名及链接
     *
     * @author 马寅广
     *
     * @date 2023/3/15 11:26
     **/
    public static void teamDeal(RunSeleniumService service, Map<String, String> teamMap, Consumer<Map.Entry<String, String>> everyTeamDeal) {
        Set<Map.Entry<String, String>> teamMapEntrySet = teamMap.entrySet();
        logger.info("共有【{}】个球队~", teamMapEntrySet.size());

        /** 执行索引 */
        int index = 1;
        for (Map.Entry<String, String> teamEntry : teamMapEntrySet) {
            logger.info("***** 球队处理进度：【{}、{}/{}】 *****", new Object[]{index++, teamEntry.getKey(), teamMapEntrySet.size()});
            //进入球队界面
            TestStep step_4 = service.getStep("step_4");
            step_4.setValue(teamEntry.getValue());
            service.runStep(step_4);

            //执行对应方法
            everyTeamDeal.accept(teamEntry);

            //进度+1
            HomeDetailController.progressAdd();
        }
    }

    /**
     * 未来比赛信息实体类映射
     *
     * @param webElementList    未来比赛信息行元素列表
     * @param targetTeamName    目标球队名称
     * @param targetTeamLink    目标球队链接
     * @param sinOrDouName      单双信息，取值：FutureMatch.DIRECTION_DOUBLE、FutureMatch.DIRECTION_SINGLE
     * @param sinOrDouNum       单双数量
     * @param futureMatchList   映射后的实体列表
     *
     * @author 马寅广
     *
     * @date 2023/3/15 11:12
     **/
    public static void entityMap(List<WebElement> webElementList, String targetTeamName, String targetTeamLink, String sinOrDouName, Integer sinOrDouNum, List<FutureMatch> futureMatchList) {
        for (WebElement webElement : webElementList) {
            List<WebElement> futureMatchTdList = webElement.findElements(By.tagName("td"));

            //实体类映射
            FutureMatch futureMatch = new FutureMatch();
            futureMatch.setLeague(futureMatchTdList.get(0).getText());
            try {
                futureMatch.setDataTime(sdf.parse(futureMatchTdList.get(1).getText()));
            } catch (ParseException e) {
                e.printStackTrace();
            }
            WebElement aWebElement = futureMatchTdList.get(2).findElement(By.tagName("a"));
            futureMatch.setMasterTeam(new Team(aWebElement.getText(), aWebElement.getAttribute("href")));
            aWebElement = futureMatchTdList.get(4).findElement(By.tagName("a"));
            futureMatch.setGuestTeam(new Team(aWebElement.getText(), aWebElement.getAttribute("href")));
            futureMatch.setHandicap(futureMatchTdList.get(5).getText());
            futureMatch.setTargetTeam(new Team(targetTeamName, targetTeamLink));
            futureMatch.setDirection(sinOrDouName == null ? null : !(Boolean) FutureMatch.directionConverter(sinOrDouName));
            futureMatch.setEvenMatch(sinOrDouNum == null ? null : new EvenMatch(sinOrDouNum, !futureMatch.getDirection()));
            futureMatchList.add(futureMatch);
        }
    }

    /**
     * 获取指定球队的近期战绩的连场单双信息
     *
     * @author 马寅广
     * @date 2024/1/4 23:45
     *
     * @param service 脚本服务
     * @param teamLink 球队链接，若为空，则认为已经进入球队界面
     *
     * @return 连场信息（List<单双（true 为单，false 为双）, 连场数>），无连场则返回 null
     **/
    public static List<Object> getEvenMatchData(RunSeleniumService service, String teamLink) {
        /** 连场信息 */
        List<Object> evenMatchData = new ArrayList<>();

        // 进入球队界面
        if (StringUtils.isNotBlank(teamLink)) {
            TestStep step_4 = service.getStep("step_4");
            step_4.setValue(teamLink);
            service.runStep(step_4);
        }

        //获取近期战绩的所有单双信息
        service.runStep("step_5");
        List<WebElement> matchList = (List<WebElement>) SeleniumUtil.globalMap.get("step_5");
        /** 单双信息 */
        List<String> sinOrDouList = matchList.stream().map(match -> match.getAttribute("textContent")).collect(Collectors.toList());

        //获取连场 ≥ 3 的连场信息
        /** 单双数量 */
        int sinOrDou = 1;
        for (int j = 0; j < sinOrDouList.size() - 1; j++) {
            if (sinOrDouList.get(j).equals(sinOrDouList.get(j + 1))) {
                sinOrDou++;
            } else {
                if (sinOrDou >= 3) {
                    evenMatchData.add("单".equals(sinOrDouList.get(j)));
                    evenMatchData.add(sinOrDou);
                    return evenMatchData;
                }
                break;
            }
        }
        return null;
    }
}
